package db

import (
	"ginhi/util/config"
	"github.com/garyburd/redigo/redis"
	"sync"
	"time"
)

var RDB *Redis
var once sync.Once

type Redis struct {
	Host        string
	Password    string
	DB          int
	Timeout     int
	MaxIdle     int
	MaxActive   int
	IdleTimeout int
	RedisPool   *redis.Pool
}

func (r *Redis) NewPool() *redis.Pool {

	return &redis.Pool{
		Dial:        r.RedisConnect,
		MaxIdle:     r.MaxIdle,
		MaxActive:   r.MaxActive,
		IdleTimeout: time.Duration(r.IdleTimeout) * time.Second,
		Wait:        true,
	}
}

func (r *Redis) RedisConnect() (redis.Conn, error) {
	c, err := redis.Dial("tcp", r.Host)
	if err != nil {
		return nil, err
	}
	_, err = c.Do("AUTH", r.Password)

	if err != nil {
		return nil, err
	}

	_, err = c.Do("SELECT", r.DB)
	if err != nil {
		return nil, err
	}

	redis.DialConnectTimeout(time.Duration(r.Timeout) * time.Second)
	redis.DialReadTimeout(time.Duration(r.Timeout) * time.Second)
	redis.DialWriteTimeout(time.Duration(r.Timeout) * time.Second)

	return c, nil
}

func (r *Redis) Get(k string) (interface{}, error) {
	c := r.RedisPool.Get()
	defer c.Close()

	v, err := c.Do("GET", k)
	if err != nil {
		return nil, err
	}
	return v, nil
}

func (r *Redis) Set(k, v string) error {
	c := r.RedisPool.Get()
	defer c.Close()
	_, err := c.Do("SET", k, v)
	return err
}

func (r *Redis) SetEx(k string, v interface{}, ex int64) error {
	c := r.RedisPool.Get()
	defer c.Close()
	_, err := c.Do("SET", k, v, "EX", ex)
	return err
}

// GetRestTime 查看缓存失效还有多长时间
func (r *Redis) GetRestTime(k string) (ex interface{}, err error) {
	c := r.RedisPool.Get()
	defer c.Close()
	ex, err = c.Do("ttl", k)
	if err != nil {
		return nil, err
	} else {
		return ex, nil
	}
}

func InitRedis() {
	once.Do(func() {
		RDB = &Redis{
			Host:        config.GetString("redis.host"),
			Password:    config.GetString("redis.password"),
			DB:          config.GetInt("redis.DB"),
			Timeout:     config.GetInt("redis.timeout"),
			MaxIdle:     config.GetInt("redis.maxIdle"),
			MaxActive:   config.GetInt("redis.maxActive"),
			IdleTimeout: config.GetInt("redis.idleTimeout"),
		}
		RDB.RedisPool = RDB.NewPool()
	})
}

func (r *Redis) Del(k string) error {
	c := r.RedisPool.Get()
	defer c.Close()
	_, err := c.Do("del", k)
	if err != nil {
		return err
	}
	return nil
}
